home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-11-10 | 61.1 KB | 2,222 lines |
- /*
- * @(#)Bignum.java 1.8 96/11/08
- *
- * Copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for NON-COMMERCIAL purposes and without
- * fee is hereby granted provided that this copyright notice
- * appears in all copies. Please refer to the file "LICENSE"
- * for further important copyright and licensing information.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
- * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
- *
- * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
- * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
- * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
- * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
- * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
- * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
- * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). SUN
- * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
- * HIGH RISK ACTIVITIES.
- */
-
-
-
- package java.lang;
- import java.util.Random;
-
- /**
- * The Bignum class represents fixed point numbers of practically
- * unlimited precision. The size of each instance depends on the
- * number of digits it represents(its precision). The precision of an
- * instance's fractional part is determined by its scale.
- *
- * <P>The rounding behaviors needed for business and scientific
- * computation often differ. To meet this requirement, the rounding
- * behavior for the class as a whole can be changed.
- *
- * <P>The Bignum class should be used for values that require high
- * precision fixed point or integer computation. Examples of this are
- * money values, security key values and values stored in databases
- * using the high precision SQL NUMERIC or DECIMAL type.
- *
- * <P>Calculations on Bignum objects always return a new Bignum object
- * with the same scale as the Bignum that performed the
- * calculation. Most operations are carried out to one extra decimal
- * place and rounded to the desired scale.
- *
- * <P>Bignum's are immutable and thread-safe.
- *
- * <P>Since Bignum values with 10's of thousands of digits can be
- * represented, the practical limit to their precision is the space
- * and time needed to work with them. The max scale value is max int;
- * the max precision of this implementation is limited only by Java's
- * maximum array size.
- *
- * <P>Bignum objects are composed of three properties: <UL>
- * <LI>Scale: The number of digits to the right of the decimal point.
- * <LI>Sign: Positive or negative.
- * <LI>Value: In this implementation, a vector of integer digits of radix 2^30.
- * </UL> */
- public final class Bignum extends java.lang.Number {
-
- /**
- * Sets the rounding option for all Bignum's in a program; the
- * default rounding option is ROUND_ABOVE_4.
- *
- * <P>All Bignum computation is done using an extra digit of
- * precision which is truncated prior to returning the result. The
- * rounding option determines how the value of this extra digit
- * affects the returned value. Rounding also applies when the
- * scale of a Bignum is reduced; here, rounding defines how the
- * value of the most significant truncated digit affects the
- * result.
- *
- * <P>If rounding causes the least signifcant digit of a result to
- * be incremented by 1, we say the result has been 'rounded up'. If
- * the least signficant digit of a result is left as is, we say the
- * result has been 'rounded down'.
- *
- * <P>The following rounding options are provided:
- *
- * <DL>
- * <DT>NO_ROUNDING: <DD>All results are rounded down regardless
- * of the value of the most significant truncated digit.
- * For example, 1.999 would round to 1.99.
- *
- * <DT>ROUND_ABOVE_4: <DD>If the value of the most significant truncated
- * digit is > 4, the result is rounded up; otherwise,
- * the result is rounded down. For example, 1.994 would
- * round down to 1.99 and 1.995 would round up to 2.00
- *
- * <DT>ROUND_ABOVE_5: <DD>If the value of the most significant truncated
- * digit is > 5, the result is rounded up; otherwise,
- * the result is rounded down. For example, 1.995 would
- * round down to 1.99 and 1.996 would round up to 2.00.
- *
- * <DT>ROUND_ALWAYS : <DD>If the value of the most significant truncated
- * digit is > 0, the result is rounded up; otherwise,
- * the result is rounded down. For example, 1.990 would
- * round down to 1.99 and 1.991 would round up to 2.00.
- *
- * <DT>ROUND_STATISTICAL : <DD>If the value of the most significant truncated
- * digit is > 5, the result is rounded up. If the value
- * of the most significant truncated digit is < 5, the
- * result is rounded down. If the value of the most
- * significant truncated digit is = 5, the result is
- * rounded down if the remaining least significant digit
- * is even; if it's odd the result is rounded up.
- * For example, 1.994 would round down to 1.99; 1.996 would
- * round up to 2.00; 1.985 would round down to 1.98; and, 1.995
- * would round up to 2.00. This option is used to help reduce
- * systematic rounding bias. See Bevington and Robinson,
- * 'Data Reduction and Error Analysis for the Physical Sciences',
- * pp. 4, McGraw Hill, Inc., (1992).
- * </DL>
- * @param val The rounding option to use for all Bignum's.
- */
-
- public static void setRoundingOption(int val) {
- switch(val) {
- case ROUND_STATISTICAL :
- roundingValue = -1;
- break;
- case NO_ROUNDING :
- roundingValue = 9;
- break;
- case ROUND_ABOVE_5 :
- roundingValue = 5 ;
- break;
- case ROUND_ABOVE_4:
- roundingValue= 4;
- break;
- case ROUND_ALWAYS:
- roundingValue = 0;
- break;
- default:
- if (val < 0 || val > 9)
- throw new IllegalArgumentException("Attempt to set invalid RoundingOption");
- break;
- }
- }
-
- /**
- * Returns the current rounding option for all Bignum's in this
- * program.
- *
- * @return current rounding option
- */
- public static int getRoundingOption() {
- return(roundingValue);
- }
-
- /**
- * Creates a Bignum from a string. The string may contain a sign
- * and a decimal point, e.g "-55.12". Spaces and other
- * non-numeric characters are ignored. Scientific notation, i.e.
- * mantissa with exponent (3E.05) is supported.
- *
- * @param s the string used to initialize the Bignum.
- */
-
- public Bignum(String s) {
- init(s,-1);
- }
-
- /**
- * Construct a Bignum given a String and an integer scale. The
- * scale represents the desired number of places to the right of
- * the decimal point.
- *
- * <P>The String may contain a sign and a decimal point,
- * e.g. "-55.12". Spaces and other non-numeric characters are
- * ignored. Scientific notation, i.e. mantissa with exponent
- * (3E.05) is supported. The scale must be an integer with value
- * greater than or equal to zero. If the scale differs from the
- * implicit decimal point given in the String the value is
- * adjusted to the given scale. This may involve rounding.
- *
- * <P>For example, Bignum("99.995",2) would result in a Bignum
- * with a scale of 2 and a value of "100.00". If the String
- * contains no decimal point, then the scale is determined solely
- * by the given integer scale. No implicit decimal point is
- * assumed. For example, the constructor Bignum("123",2) creates
- * a Bignum with a scale of 2 and a value of
- * "123.00".
- *
- * <P><B>Note:</B> Rounding is controlled by the roundingIndex
- * function.
- *
- * @param s the string used to initialize the Bignum.
- * @param scale the value greater than or equal to zero
- * representing the desired number of digits to the right of the
- * decimal point.
- */
- public Bignum(String s,int scale) {
- verifyScale(scale);
- init(s,scale);
- }
-
- /**
- * Construct a Bignum from an integer given an integer value and
- * an integer scale. The scale is set to the value specified. No
- * implicit decimal point is assumed, i.e., if the integer value is
- * "1234" and the scale 2, the resulting Bignum will be "1234.00.
- *
- * @param x The int used to initialize the new Bignum.
- * @param scale The desired number of digits after the decimal point.
- */
- public Bignum(int x,int scale) {
- verifyScale(scale);
- if(x < 0) {
- negative = true;
- x *= -1;
- if(x < 0) {
- int[] v = {0,2};
- value = v;
- _setScale(scale);
- return;
- }
- }
- else
- negative = false;
- int digit0 = (int)(x & MASK);
- long carry = (long)x >> SRADIX;
- int digit1 = (int) (carry & MASK);
-
- if(digit1 > 0) {
- int[] v = {digit0,digit1};
- value = v;
- }
- else {
- int [] v = {digit0};
- value = v;
- }
- _setScale(scale);
- }
- /**
- * Construct a Bignum from an integer given an integer value.
- * The scale is set to zero.
- *
- * @param x The long used to initialize the new Bignum.
- */
- public Bignum(int x) {
- this(x,0);
- }
- /**
- * Construct a Bignum from a long integer given a long value and
- * an integer scale. The scale is set to the value specified. No
- * implicit decimal point is assumed, i.e., if the long value is
- * "1234" and the scale 2, the resulting Bignum will be "1234.00.
- *
- * @param x The long value used to initialize the new Bignum.
- * @param scale The desired number of digits after the decimal point.
- */
- public Bignum(long x,int scale) {
- verifyScale(scale);
-
- if(x < 0) {
- negative = true;
- x *= -1L;
- if(x < 0) {
- int[] v = {0,0,8};
- value = v;
- _setScale(scale);
- return;
- }
- }
- else
- negative = false;
- int digit0 = (int)(x & MASK);
- long carry = x >> SRADIX;
- int digit1 = (int) (carry & MASK);
- carry = carry >> SRADIX;
- int digit2 = (int) (carry & MASK);
- if(digit2 > 0) {
- int[] v= {digit0,digit1,digit2};
- value = v;
- }
- else
- if(digit1 > 0) {
- int[] v = {digit0,digit1};
- value = v;
- }
- else {
- int [] v = {digit0};
- value = v;
- }
- _setScale(scale);
- }
- /**
- * Construct a Bignum from a long integer given a long integer value.
- * The scale is set to zero.
- *
- * @param x The long used to initialize the new Bignum.
- */
- public Bignum(long x) {
- this(x,0);
- }
-
- /**
- * Construct a Bignum from a double given a double value and an
- * integer scale. The scale is set to the value specified. No
- * implicit decimal point is assumed, i.e., if the double value is
- * "1234" and the scale 2, the resulting Bignum will be "1234.00.
- * If the double value is "1234.5" and the scale 2 the value will
- * be "1234.50". Rounding may occur during this conversion.
- *
- * @param x The double value used to initialize the new Bignum.
- * @param scale The desired number of digits after the decimal point.
- */
- public Bignum(double x, int scale) {
- verifyScale(scale);
- Double d = new Double(x);//I'm going to have to redo this to
- init(d.toString(),scale);// calculate exponent and fraction
- //This is a cheat.
- }
-
- /**
- * Construct a Bignum from another Bignum. The
- * scale and value of the new Bignum are copied from the Bignum
- * given in the argument.
- *
- * @param x The Bignum used to initialize the new Bignum.
- */
- public Bignum(Bignum x) {
- scale = x.scale;
- value = new int[x.value.length];
- System.arraycopy(x.value,0,value,0,value.length);
- negative = x.negative;
- }
-
- /**
- * Given an existing Bignum and an integer scale value, construct
- * a new Bignum with the scale adjusted accordingly. The
- * scale and value of the new Bignum are copied from
- * the argument Bignum. The scale is then adjusted to the scale
- * given as a parameter. This may result in rounding of the value.
- *
- * @param x The Bignum to copy.
- * @param scale An integer representing the desired * scale of the
- * new Bignum.
- */
- public Bignum(Bignum x, int scale) {
- verifyScale(scale);
- this.scale = x.scale;
- value = new int[x.value.length];
- System.arraycopy(x.value,0,value,0,value.length);
- negative = x.negative;
- if (this.scale != scale) {
- _setScale(scale);
- }
- }
- //----------------------Static Factory Methods----------------------------
- /**
- * Return a Bignum created from the given byte array.
- * The array is treated as a string of bits representing an unsigned
- * integer, with the most significant bit at the 0th position. This
- * function is supplied to simplify and optimize operations in
- * algorithms using large integers, such as hashing calculations.
- *
- * @param byteArray An array of bytes holding the bitstring value of
- * the desired Bignum.
- * @return A new Bignum whose value is determined by the given byte array.
- */
- public static Bignum createFromByteArray(byte[] byteArray) {
- Bignum r = new Bignum(0);
- int numBits = byteArray.length * 8;
- int numWords = (numBits + (SRADIX - 1)) / SRADIX;
-
- r.scale = 0;
- r.negative = false;
- r.value = new int [numWords];
-
- // byteArray[] is big-endian, base256; value[] is little-endian
- // and base 2^SRADIX. this stuffs bits into value[], LSB first.
-
- for (int i = byteArray.length - 1, digit = 0; i >= 0; i--) {
- int bits, bitOffset;
-
- bits = byteArray [i] & 0x0ff;
- bitOffset = ((byteArray.length - i - 1) * 8) % SRADIX;
- r.value [digit] |= (bits << bitOffset) & MASK;
-
- bitOffset = SRADIX - bitOffset;
- if (bitOffset <= 8) {
- digit++;
- if (bitOffset < 8)
- r.value [digit] |= (bits >>> bitOffset);
- }
- }//for
-
- return r;
- }
- /**
- * Returns a byte array derived from the value of the numeric.
- * The array is considered a string of bits with the most significant bit
- * at the 0th position.This function should be used with great caution.
- * It is supplied to simplify and optimize calculations in algorithms that
- * used hashing calculations, e.g. many security algorithms.
- * @returns A byte array derived from the value of the Bignum
- */
- public byte[] toByteArray(){
- int i,j;
- i = significantBits();
- if(i <= 0) {
- byte[] b = new byte[1];
- b[0] = 0x00;
- }
- j = i/8;
- if(i%8 >0) j++;
-
- byte [] outArray = new byte[j];
-
- int[] r = new int[value.length];
- System.arraycopy(value,0,r,0,value.length);
- for(j=outArray.length - 1;j >= 0; j--) {
- outArray[j] = (byte)(r[0] & 0x000000FF);
- int carry = 0;
- for (i=value.length - 1; i>=0; --i) {
- int val = r[i];
- r[i] = (val>>>8) | carry;
- carry = (int)((val<<(SRADIX-8)) & MASK);
- }
- }
- return outArray;
- }
-
- /**
- * Return a Bignum created from the given Integer array.
- * The array is considered a string of bits with the least significant bit
- * at the 0th position. This function should be used with great caution.
- * It is supplied to simplify and optimize calculations in algorithms that
- * used hashing calculations, e.g. many security algorithms.
- * @param intArray An array of integers holding the desired value of the new Bignum.
- * @return A new Bignum whose value is determined by the given integer array.
- */
- public static Bignum createFromIntegerArray(int [] intArray) {
- int[] t1 = new int[intArray.length + 1];
- for(int i = 0; i < intArray.length;i++){
- t1[i] = (int)(intArray[i] & MASK);
- }
- Bignum r = new Bignum(t1);
- r.scale = 0;
- r.negative = false;
-
- return r;
- }
- /**
- * Return a Bignum value created by dividing the argument by
- * 10**scale. Thus, createFromScaled(504,2) would create the
- * value "5.04". A negative scale throws an IllegalArgumentException.
- *
- * @param scaled The scaled value as a long.
- * @param s The desired scale value
- * @return A new Bignum.
- */
- public static Bignum createFromScaled(long scaled, int s) {
- verifyScale(s);
- Bignum n = new Bignum(scaled);
- if (s != 0)
- n.scale = s;
- return n;
- }
-
- /**
- * Return a Bignum created from the given string and radix.
- * Decimal places are ignored and the scale is set to zero.
- * The string may contain a sign.
- * @param s A string containing the intended value of the Bignum.
- * @param radix The base of the string representation.
- * @return A new Bignum whose value is given by the string argument.
- */
- public static Bignum createFromRadixString(String s, int radix) {
- Bignum r = new Bignum(0);
- r.scale = 0;
- r.negative = false;
- r.value = new int[s.length()/(radix/2) + 1];
-
- int[] t1;
- //char maxChar = Character.forDigit(radix - 1,radix);
- int a;
- char c;
- boolean gotFirstDigit = false;
- for (int i = 0;i < s.length() ;i++ ) {
- c = s.charAt(i);
- a = Character.digit(c,radix);
- if(a >= 0){
- gotFirstDigit = true;
- t1 = mulAndAdd(r.value,radix,a);
- if(t1 != null)
- r.value = t1;
- continue;
- }
- if (c == '-' && !gotFirstDigit) {
- r.negative = true;
- continue;
- }
- }//for
- return r;
- }
- /**
- *Random number generator
- *Returns a random number using randomSeed as a seed and with a number of bits of up to bitSize.
- *@param bitSize The position of the most significant bit in the random number
- *@param randomSeed a Random number used as the seed for the random number generated
- *@return a new Bignum of maximium size bitSize
- */
- public static Bignum random(int bits, Random randomSeed){
- int ni = (bits-1)/SRADIX + 1;
- int i;
- bits = bits % SRADIX;
- int[] rs = new int[ni];
- for (i=0; i<ni; ++i) {
- int r = (int) (randomSeed.nextInt() & MASK);
- rs[i] = r;
- }
- rs[ni-1] &= (1<<bits)-1;
- Bignum rslt = new Bignum(rs);
- rslt.dropLeadingZeroes();
- return rslt;
- }
-
-
- /**
- * The following methods convert the Bignum value to an
- * appropriate Java built-in type. Note that these conversions
- * may result in a loss of precision.
- *
- */
-
- /**
- * Convert the Bignum value an int.
- * This conversion may result in a loss of precision. Digits
- * after the decimal point are dropped.
- *
- * @return An int value representation of the Bignum.
- */
- public int intValue() {
- return ((int)longValue());
- }
-
- /**
- * Convert the Bignum value to a long.
- * This conversion may result in a loss of precision. Digits
- * after the decimal point are dropped.
- *
- * @return A long value representation of the Bignum.
- */
- public long longValue() {
- Bignum temp = new Bignum(this);
- temp._setScale(0);
- long lv = 0;
- int i = temp.value.length < 3 ? temp.value.length - 1: 2;
-
- for(;i >= 0;i--){
- lv = (lv << SRADIX) + temp.value[i];
- }
- return temp.negative? -lv : lv;
- }
-
- /**
- * Convert the Bignum value to a float.
- * This conversion may result in a loss of precision.
- *
- * @return A float value representation of the Bignum.
- */
- public float floatValue() {
- return ((float) doubleValue());
- }
-
- /**
- * Convert the Bignum value to a double.
- * This conversion may result in a loss of precision.
- *
- * @return A double value representation of the Bignum.
- */
- public double doubleValue() {
- Bignum temp = new Bignum(this);
- temp._setScale(0);
- double d=0.0;
- int m = value.length - 1;
- m = m > 4? m - 4 : 0;
- for(int i=value.length - 1;i>=m;i--) {
- d = d * MASK + (double) value[i];
- }
- if(m > 0)
- d = d * Math.pow(SRADIX,m);
- temp = this.subtract(temp);
-
- if (scale != 0) {
- double s = 1;
- s = Math.pow(10,scale);
- d = d/s;
- }
- return negative? -d : d;
- }
-
-
- /**
- * Convert the Bignum value to a String.
- * Negative numbers are represented by a leading "-". No sign is
- * added for positive numbers.
- *
- * @return A String representation of the Bignum.
- */
- public String toString() {
- if(value == null)
- return "null";
- int l = value.length * 10 + 2;
-
- if(l < scale)
- l = scale + 2;
-
- char[] x = new char[l];
- int xi=x.length - 1;
- int dp = xi - scale;
- if(scale == 0)
- dp = -9999;
- int[] temp = new int[value.length];
- System.arraycopy(value,0,temp,0,temp.length);
- for (int i=temp.length - 1; i >= 0;) {
- if(temp[i] == 0){
- i--;
- continue;
- }
- int rem = div0(temp,temp,10);
- x[xi--] = Character.forDigit(rem,10);
- if(xi == dp) xi--;
- }
- if(xi == x.length - 1) //was value all zeroes?
- x[xi--] = '0';
- if(dp > 0){
- while(xi > dp)
- x[xi--] = '0';
- x[dp] = '.';
- }
- String ms = negative ? "-":"";
- ms += (new String(x,xi,x.length - xi)).trim();
- return ms;
- }
-
- /**
- * Returns a String representation of the Bignum in the given radix.
- * In this version scaling is ignored for any radix other than 10.
- * @param radix the base of the number to be returned
- * @return a String representation of the Bignum in the given radix
- */
- public String toString(int radix) {
- if(radix == 10)
- return toString();
-
- if(value == null)
- return "null";
-
- StringBuffer sb = new StringBuffer();
- int[] temp = new int[value.length];
- int len = 0;
- System.arraycopy(value,0,temp,0,temp.length);
- for (int i=temp.length - 1; i >= 0;) {
- if(temp[i] == 0){
- i--;
- continue;
- }
- int rem = div0(temp,temp,radix);
- sb.insert(0,Character.forDigit(rem,radix));
- len++;
- }
- if(len==0)
- sb.insert(0,'0');
- String ms = negative ? "-":"";
- ms += (sb.toString()).trim();
- return ms;
-
- }
-
-
- /**
- * Return the number of digits to the right of the decimal point.
- *
- *
- * @return An integer value representing the number of decimal
- * places to the right of the decimal point.
- */
- public int getScale() {
- return (scale);
- }
-
-
- //-----------------------------Arithmetic Operations------------------
- /**
- * Returns the arithmetic sum of the Bignum and the argument.
- * The scale of the sum is determined by this object not by the
- * argument. The calculation is performed using a
- * scale equal to the greater scale of the two operands. Rounding is
- * applied to the result.
- *
- * @param n The Bignum to add.
- * @return The sum as a Bignum.
- */
- public Bignum add(Bignum n) {
- Bignum result= new Bignum(this);
- Bignum x;
- if(scale != n.scale){
- x = new Bignum(n);
- x._setScale(scale);
- }
- else
- x = n;
- //signs match
- if (result.negative == x.negative) {
- result.value = add0(result.value,x.value);
- return (result);
- }
- //result is positive
- if (!result.negative) {
- int cmp = result.compareAbs(x);
- if (cmp < 0) { //abs value of result is less
- result.value = sub0(x.value,result.value);
- result.negative = x.negative;
- return (result);
- } else {
- if (cmp > 0) { //abs value of result is greater
- result.value = sub0(result.value,x.value);
- return (result);
- } else { //abs values are equal
- result.zero();
- return (result);
-
- }
- }
- }
-
- //result is negative
- int cmp = result.compareAbs(x);
- if (cmp < 0) { //abs value of result is less
- result.value = sub0(x.value,result.value);
- result.negative = x.negative;
- return (result);
- } else {
- if (cmp > 0) { //abs value of result is greater
- result.value = sub0(result.value,x.value);
-
- return (result);
- }
- }
- //abs values are equal
- result.zero();
- return (result);
- }
-
- /**
- * Returns the arithmetic difference between the Bignum and the
- * argument. The scale of the difference is determined by this object
- * not by the argument. The calculation is performed using a
- * scale equal to the greater scale of the two operands. Rounding is
- * applied to the result.
- *
- * @param n The Bignum to subtract.
- * @return The difference as a Bignum.
- */
- public Bignum subtract(Bignum n) {
- Bignum result = new Bignum(this);
- Bignum x;
- if(result.scale != n.scale) {
- if(result.scale > n.scale) {
- x = new Bignum(n);
- x._setScale(result.scale);
- }
- else {
- x = n;
- result._setScale(x.scale);
- }
- }
- else
- x = n;
-
- if (result.negative == false && x.negative == false) {
- switch(result.compareAbs(x)) {
- case 0:
- result.zero();
- break;
- case 1:
- result.value = sub0(result.value,x.value);
- break;
- default:
- result.value = sub0(x.value,result.value);
- result.negative = true;
- }
- if(result.scale != this.scale)
- result._setScale(this.scale);
- return (result);
- }
-
- if (result.negative == false && x.negative == true) {
- result.value = add0(result.value,x.value);
- }
- else if (result.negative == true && x.negative == false) {
- result.value = add0(result.value,x.value);
- }
- else {
- switch(result.compareAbs(x)) {
- case 0:
- result.zero();
- break;
- case 1:
- result.value = sub0(result.value,x.value);
- result.negative = true;
- break;
- default:
- result.value = sub0(x.value,result.value);
- result.negative = false;
- }
- }
- if(result.scale != this.scale)
- result._setScale(this.scale);
-
- return (result);
- }
-
- /**
- * Returns the arithmetic product of the object Bignum and the
- * argument. The scale of the product is determined by this object
- * not by the argument.
- *
- * @param x The multiplier as a Bignum.
- * @return The product as a Bignum.
- */
- public Bignum multiply(Bignum x) {
-
- Bignum prod = new Bignum(this); //product
- Bignum m; //multiplicand
- Bignum mx; //multiplier
-
- prod.scale += x.scale;
- prod.negative = (negative == x.negative? false: true);
-
- if (value.length > x.value.length) {
- //use the smallest number as the multiplier
- m = this;
- mx = x;
- } else {
- m = x;
- mx = this;
- }
- if(mx.value.length == 1)
- prod.value = mul0(m.value,mx.value[0]);//use the faster single digit multiply
- else
- prod.value = mul0(m.value,mx.value);
-
- if(prod.scale != scale)
- prod._setScale(scale);
- prod.dropLeadingZeroes();
- return (prod);
- }
-
- /**
- * Returns the arithmetic quotient calculated by dividing the
- * Bignum by the argument. The scale of the quotient is
- * determined by this object not by the argument.
- *
- * @param x The divisor as a Bignum.
- * @return The quotient as a Bignum.
- */
-
- public Bignum divide(Bignum x) {
- if (x.compareAbs(Bignum.ZERO) == 0) {
- throw new ArithmeticException("Division by zero");
- }
-
- Bignum dividend = new Bignum(this);
- Bignum divisor = new Bignum(x);
-
- dividend.dropLeadingZeroes();
- divisor.dropLeadingZeroes();
- //scaling for decimal places
- if(roundingValue < 9 || (divisor.scale > dividend.scale)) {
- int scaleFactor = divisor.scale + 1;
- dividend.scale++;
- int m1 = 9; //this is approx log10 of BASE
- int m4 = 1000000000;
- int x1 = scaleFactor;
- for(;x1 >= m1;x1 -= m1 )
- dividend.value = mul0(dividend.value,m4);
- if(x1 > 0 )
- dividend.value = mul0(dividend.value,pow(10,x1));
- }
-
- //----------------------------------------------------------------
- Bignum quot = new Bignum(new int[(dividend.value.length - divisor.value.length) + 1]);
- quot.negative = divisor.negative ? !dividend.negative : dividend.negative;
- quot.scale = dividend.scale;
- if(divisor.value.length == 1){
- //if divisor is only 1 digit use quick division
- //remainder can only be an int
- div0(quot.value,dividend.value,divisor.value[0]);
- quot._setScale(scale);
- return quot;
- }
- //Next normalize the dividend and divisor, i.e. divisor[leftmostDigit] >= BASE/2
- //
- int vLeftmostDigit = divisor.value[divisor.value.length - 1];
- if(vLeftmostDigit >= (BASE)/2){
- int[] tvalue = new int[dividend.value.length + 1];
- System.arraycopy(dividend.value, 0, tvalue, 0, dividend.value.length);
- tvalue[tvalue.length - 1] = 0;
- dividend.value = tvalue;
- div (dividend, divisor, quot);
- } else {
- int[] tvalue = new int[dividend.value.length + 1];
- System.arraycopy(dividend.value,0,tvalue,0,dividend.value.length);
- int d = (BASE)/(vLeftmostDigit + 1);
- dividend.value = mul0(tvalue,d);
- divisor.value = mul0(divisor.value,d);
- div (dividend, divisor, quot);
- }
- quot._setScale(scale);
- return quot;
- }
- /**
- * Returns an array of two Bignum objects. The first element in
- * the array holds the quotient value resulting from the arithmetic
- * division of this Bignum object by the argument. The second element
- * in the array holds the remainder.
- *
- * @param x The divisor as a Bignum.
- * @return An array of two Bignum objects containing the quotient and
- * remainder of the division.
- */
-
- public Bignum[] integerDivide(Bignum x) {
- if (x.compareAbs(Bignum.ZERO) == 0) {
- throw new ArithmeticException("Division by zero");
- }
-
- Bignum dividend = new Bignum(this);
- Bignum divisor = new Bignum(x);
- Bignum quot = _intDivide(divisor,dividend,scale);
-
- Bignum[] r = {quot,dividend};
- return r;
- }
-
-
- /* Private helper function for performing integer division
- * and remainder arithmetic.
- * the remainder is returned in dividend
- */
- static private Bignum _intDivide(Bignum divisor,Bignum dividend, int scale){
-
-
- dividend.dropLeadingZeroes();
- divisor.dropLeadingZeroes();
-
-
- //scaling for decimal places
- if(divisor.scale > dividend.scale) {
- int scaleFactor = divisor.scale;// + 1;
- //dividend.scale++;
- int m1 = 9; //this is approx log10 of BASE
- int m4 = 1000000000;
- int x1 = scaleFactor;
- for(;x1 >= m1;x1 -= m1 )
- dividend.value = mul0(dividend.value,m4);
- if(x1 > 0 )
- dividend.value = mul0(dividend.value,pow(10,x1));
- }
-
- //--------------------------------------------------------------------
- if(dividend.lessThan(divisor)){
- return new Bignum(0,0);
- }
- Bignum quot = new Bignum(new int[(dividend.value.length - divisor.value.length) + 1]);
- quot.negative = divisor.negative ? !dividend.negative : dividend.negative;
- if(dividend.scale >= divisor.scale)
- quot.scale = dividend.scale - divisor.scale;
- else
- quot.scale = 0;
-
- //if divisor is only 1 digit use quick division
- if(divisor.value.length == 1){
- //remainder can only be an int
- int rem = div0(quot.value,dividend.value,divisor.value[0]);
- dividend.zero();
- dividend.value[0] = (int) (rem & MASK);
- long carry = (long)rem >> SRADIX;
- int digit1 = (int) (carry & MASK);
- if (digit1 > 0) {
- if(dividend.value.length < 2 ) {
- int[] newval = {dividend.value[0],digit1};
- dividend.value = newval;
- }
- else
- dividend.value[1] = digit1;
- }
- if(quot.scale > 0)
- return truncate(quot);
- else
- return quot;
- }
- //Next normalize the dividend and divisor, i.e. divisor[leftmostDigit] >= BASE/2
- //
- int vLeftmostDigit = divisor.value[divisor.value.length - 1];
-
- if(vLeftmostDigit >= (BASE)/2){
- int[] tvalue = new int[dividend.value.length + 1];
- System.arraycopy(dividend.value, 0, tvalue, 0, dividend.value.length);
- tvalue[tvalue.length - 1] = 0;
- dividend.value = tvalue;
- div (dividend, divisor, quot);
- } else {
- int[] tvalue = new int[dividend.value.length + 1];
- System.arraycopy(dividend.value,0,tvalue,0,dividend.value.length);
- int d = (BASE)/(vLeftmostDigit + 1);
- dividend.value = mul0(tvalue,d);
- divisor.value = mul0(divisor.value,d);
- div (dividend, divisor, quot);
- div0(dividend.value,dividend.value,d);
- }
-
- //quot._setScale(scale);
-
- if(quot.scale > 0) {
- quot = truncate(quot);
-
- }
-
- return quot;
-
- }
- /**
- * Returns the arithmentic remainder calculated by dividing this
- * Bignum object by the argument. No rounding is performed.
- *
- * @param x The divisor as a Bignum.
- * @return The remainder as a Bignum.
- */
- public Bignum remainder(Bignum x) {
- if (x.compareAbs(Bignum.ZERO) == 0) {
- throw new ArithmeticException("Division by zero");
- }
-
- if(this.lessThan(x))
- return new Bignum(this);
-
- Bignum dividend = new Bignum(this);
- Bignum divisor = new Bignum(x);
- _intDivide(divisor,dividend,scale);
- return dividend;
- }
-
-
-
-
- /**
- * Square root
- * Returns the square root of this Bignum.
- * @return the square root of this Bignum.
- */
- public Bignum sqrt() {
-
- // Uses a Newtonian convergence algorithm.
- Bignum g = new Bignum(this,scale + 1);
- Bignum temp = new Bignum(0);
- div0(g.value,g.value,2);
- Bignum eps = createFromScaled(5,g.scale);
- Bignum diff = (g.multiply(g)).subtract(this);
- while(diff.compareAbs(eps) > 0){
- temp.value = mul0(g.value,2);
- temp.scale = g.scale;
- temp.negative = g.negative;
-
- temp = diff.divide(temp);
- g = g.subtract(temp);
- temp = g.multiply(g);
-
- diff = temp.subtract(this);
- }
- return g;
- }
-
- /**
- * Returns a new Bignum whose value is calculated by
- * raising this Bignum to the power of the given exponent.
- * @param e An integer value cotaining the exponent to be used.
- * @return this Bignum raised to the power given by the exponent argument.
- */
-
- public Bignum pow(int e) {
- //A binary power algorithm is used.
- if(e==0) return new Bignum(1.0,scale);
- Bignum ans = new Bignum(this);
- int[] t = {1};
- while(e > 1) {
- if((e & 0x0001)==0x0001){
- t = mul0(t, ans.value);
- }
- ans.value = mul0(ans.value,ans.value);
- e >>=1;
- }
- ans.value = mul0(ans.value,t);
- ans.dropLeadingZeroes();
- return ans;
- }
-
- /**
- * Returns true if the arithmetic value of the Bignum equals the
- * argument.
- *
- * @param obj The object to compare.
- * @return The boolean result of the comparison.
- */
- public boolean equals(Object obj) {
- Bignum x = (Bignum) obj;
- if (compare(x) == 0) {
- return (true);
- }
- return (false);
- }
-
- /**
- * Returns true if the arithmetic value of the Bignum is less
- * than the argument.
- *
- * @param x The object to compare.
- * @return The boolean result of the comparison.
- */
- public boolean lessThan(Bignum x) {
- if (compare(x) == -1) {
- return (true);
- }
- return (false);
- }
-
- /**
- * Returns true if the arithmetic value of the Bignum is less
- * than or equals the argument.
- *
- * @param x The object to compare.
- * @return The boolean result of the comparison.
- */
- public boolean lessThanOrEquals(Bignum x) {
- if (compare(x) != 1) {
- return (true);
- }
- return (false);
- }
-
- /**
- * Returns true if the arithmetic value of the Bignum is greater
- * than the argument.
- *
- * @param x The object to compare.
- * @return The boolean result of the comparison.
- */
- public boolean greaterThan(Bignum x) {
- if (compare(x) == 1) {
- return (true);
- }
- return (false);
- }
-
- /**
- * Returns true if the arithmetic value of the Bignum is greater
- * than or equals the argument.
- *
- * @param x The object to compare.
- * @return The boolean result of the comparison.
- */
- public boolean greaterThanOrEquals(Bignum x) {
- if (compare(x) != -1) {
- return (true);
- }
- return (false);
- }
-
- /**
- * Returns an integer hashcode for the Bignum.
- *
- * @return The hashcode as an integer.
- */
- public int hashCode() {
- int hash = 0;
- for(int i = 0; i < value.length; i++) {
- try {
- hash += value[i];
- }catch(Exception ex){
- hash = 0;
- }
-
- }
- return hash;
- }
-
- /**
- * Returns a Bignum copied from the current object with the scale
- * set as specified by the argument. Note that changing the scale
- * to a smaller value may result in rounding.
- *
- * @param scale the character to be converted
- * @return A Bignum with the adjusted scale.
- * @see Bignum#setRoundingOption
- */
- public Bignum setScale(int scale) {
- verifyScale(scale);
- Bignum x = new Bignum(this,scale);
- return (x);
- }
- //------------------------------Bit Operations------------------------
- /**
- *Returns the number of significant bits in the Bignum.
- *@return an integer containing the number of the most significant bit
- * of this Bignum.
- */
- public int significantBits() {
- int i;
- for(i = value.length - 1; i >= 0 && value[i] == 0;--i);
- if(i < 0)
- return 0;
- int val = value[i];
- int l = i;
- i = 0;
- while(val !=0){
- val >>>=1;
- ++i;
- }
-
- l = l * SRADIX;
- return l + i;
- }
- /**
- * Returns a new Bignum whose value is calculated by shifting this
- * Bignum to the left by the number of bits given in shiftBits
- *
- * @param shiftBits the number of bits to shift.
- * @return A new Bignum whose value is this Bignum / 2^shiftBits
- */
- public Bignum shiftRight(int shiftBits){
- if(shiftBits < 0)
- throw new IllegalArgumentException("Number of bits to shift may not be negative");
-
- int nw = shiftBits / SRADIX;
- shiftBits %= SRADIX;
- int[] r = new int[value.length - nw];
- System.arraycopy(value,nw,r,0,value.length - nw);
- int i;
- int carry = 0;
- for (i=r.length - 1; i>=0; --i) {
- int val = r[i];
- r[i] = (val>>>shiftBits) | carry;
- carry = (int)((val<<(SRADIX-shiftBits)) & MASK);
- }
- Bignum result = new Bignum(r);
- result.dropLeadingZeroes();
- return result;
-
- }
- /**
- * Returns a new Bignum calculated by shifting this Bignum to the
- * left by the number of bits given in shiftBits.
- *
- * @param shiftBits The number of bits to shift
- * @return A new Bignum whose value is this Bignum * 2^shiftBits
- */
- public Bignum shiftLeft(int shiftBits){
- if(shiftBits < 0)
- throw new IllegalArgumentException("Number of bits to shift may not be negative");
- int nw = shiftBits / SRADIX;
- shiftBits %= SRADIX;
- int[] r = new int[value.length + nw + 1];
-
- System.arraycopy(value, 0, r, nw, value.length);
-
- int i;
- int carry = 0;
- for (i=0; i< r.length - 1; ++i) {
- int val = r[i];
- r[i] = (int)((val<<shiftBits) | carry & MASK);
- carry = val >>>(SRADIX - shiftBits);
- }
- if(carry != 0)
- r[r.length -1] = carry;
-
- Bignum result = new Bignum(r);
- result.dropLeadingZeroes();
- return result;
- }
-
- //------------------------------Modular Arithmetic----------------------
- /**
- * Returns the modular multiplicative inverse of this Bignum
- * @param mod the modulus to be used
- * @return the modular multiplicative inverse of this Bignum using "mod" as
- * the modulus
- */
- public Bignum modInverse(Bignum mod) {
- Bignum i = new Bignum(mod);
- Bignum h = new Bignum(this);
- Bignum v = new Bignum(ZERO);
- Bignum d = new Bignum(1);
- while(h.greaterThan(ZERO)) {
- Bignum tt[] = i.integerDivide(h);
- Bignum t = tt[0];
- Bignum x = h;
- h = i.subtract(t.multiply(x));
- i = x;
- x = d;
- d = v.subtract(t.multiply(x));
- v = x;
-
- }
- if(!v.negative)
- return v.remainder(mod);
- Bignum m = (v.remainder(mod)).multiply(mod);
- return(v.subtract(m));
-
-
- }
-
- /**
- * Modular exponentiation. Calculates a new Bignum
- * @param exponent the exponent to be used
- * @param mod the modulus to be used
- * @return a new Bignum whose values is this^exponent mod "mod".
- */
-
- public Bignum modExp (Bignum exponent, Bignum mod){
- int ipr = exponent.significantBits() - 1;
- int ibit = 1 << (ipr % SRADIX);
- ipr = ipr / SRADIX;
- int[] t = new int[value.length + 1];
- Bignum rslt = new Bignum(ONE);
- while (ipr >= 0) {
-
- rslt.value = mul0(rslt.value,rslt.value,t);
- if(rslt.value != t)
- t = rslt.value;
- rslt = rslt.remainder(mod);
- if ((exponent.value[ipr] & ibit) != 0) {
- for(int i = 0; i < t.length;i++) t[i] = 0;
- rslt.value = mul0(rslt.value,this.value,t);
- if(rslt.value != t)
- t = rslt.value;
- rslt = rslt.remainder(mod);
- }
- ibit >>>= 1;
- if (ibit==0) {
- --ipr;
- ibit = 1<<(SRADIX-1);
- }
- for(int i = 0; i < t.length;i++) t[i] = 0;
- }
- return rslt;
- }
- //----------------------Prime Number Testing----------------------------
- private static int[] smallPrimes = new int[51];
-
- static {
- smallPrimes[0] = 2;
- smallPrimes[1] = 3;
- smallPrimes[2] = 5;
- smallPrimes[3] = 7;
- smallPrimes[4] = 11;
- smallPrimes[5] = 13;
- smallPrimes[6] = 17;
- smallPrimes[7] = 19;
- smallPrimes[8] = 23;
- smallPrimes[9] = 29;
- smallPrimes[10] =31;
- smallPrimes[11] =37;
- smallPrimes[12] =41;
- smallPrimes[13] =43;
- smallPrimes[14] =47;
- smallPrimes[15] =53;
- smallPrimes[16] =59;
- smallPrimes[17] =61;
- smallPrimes[18] =67;
- smallPrimes[19] =71;
- smallPrimes[20] =73;
- smallPrimes[21] =79;
- smallPrimes[22] =83;
- smallPrimes[23] =89;
- smallPrimes[24] =97;
- smallPrimes[25] =101;
- smallPrimes[26] =103;
- smallPrimes[27] =107;
- smallPrimes[28] =109;
- smallPrimes[29] =113;
- smallPrimes[30] =127;
- smallPrimes[31] =131;
- smallPrimes[32] =137;
- smallPrimes[33] =139;
- smallPrimes[34] =149;
- smallPrimes[35] =151;
- smallPrimes[36] =157;
- smallPrimes[37] =163;
- smallPrimes[38] =167;
- smallPrimes[39] =173;
- smallPrimes[40] =179;
- smallPrimes[41] =181;
- smallPrimes[42] =191;
- smallPrimes[43] =193;
- smallPrimes[44] =197;
- smallPrimes[45] =199;
- smallPrimes[46] =211;
- smallPrimes[47] =223;
- smallPrimes[48] =227;
- smallPrimes[49] =229;
- smallPrimes[50] =233;
- }
-
- /**
- * This method tests for primality, first by attempting to divide
- * by a few small primes, then by using the Rabin probabilistic
- * primality test 50 times. The probability of failing this test
- * is less than 1 / (4^n).
- *
- * @return a boolean, true if this Bignum is probably prime, false
- * otherwise.
- */
- public boolean isProbablePrime() {
- Bignum n1, n2;
- // test to see if this is divisible by a small prime.
- if((value[0] & 0x00000001) != 0x00000001) //make sure its odd
- return equals( TWO);
- for (int i = 1; i < 11 ; i++) {
- int prime = smallPrimes[i];
- if (quickMod(prime) == 0)
- if(value[0] != prime)
- return false;
- }
- // use a probabilistic test on this
- return isProbablePrime0(50);
- }
- private int quickMod(int d) {
- int rem = 0;
- int i = value.length;
- while (i-- > 0) {
- long temp = (long) (((value[i]) <<32) | rem);
- rem = (int)(temp % d);
- }
- if(negative && rem !=0)
- rem = d - rem;
- return rem;
-
- }
-
- private boolean isProbablePrime0(int n) {
- Bignum wm1 = subtract(ONE);
- //calculate a = largest power of 2 that divides wm1
- int a = 0;
- int l = 0;
- for(int i = 0;i < wm1.value.length && wm1.value[i] == 0;l++,i++);
- int val = wm1.value[l];
- while((val & 1) ==0) {
- a++;
- val >>>= 1;
- }
- a = l * SRADIX + a;
- if(a == 0 ) //wm1 is odd so w must be even
- return false;
-
- int j;
- Bignum m = wm1.shiftRight(a);
-
- Bignum z = new Bignum(3);
- //System.out.println(m.toString(16));
-
- z = z.modExp(m,this);
- //System.out.println(z.toString(16));
- if (z.equals(ONE) || z.equals(wm1))
- return true;
- for (j=1; j<a; j++)
- {
- z = z.multiply(z);
- z = z.remainder(this);
- if (z.equals(wm1))
- return true;
- if (z.equals(ONE))
- return false;
- }
-
- int s = wm1.significantBits();
-
- for(int i = 0; i < n; i++) {
- //System.out.println("Round: " + i);
- Bignum b = random(s,new Random());
- if(b.greaterThan(wm1))
- b = b.remainder(wm1);
- z = b.modExp(m, this);
- if(z.equals(ONE) || z.equals(wm1))
- continue;
- for(j=1;j<a;j++){
- z = z.modExp(TWO,this);
- if(z.equals(wm1))
- break;
- if(z.equals(ONE))
- return false;
- }
- if(j == a)
- return false;
-
- }
-
- return true;
- }
- //---------------------------Miscellaneous Operations------------------
- // public constants
- public final static int ROUND_STATISTICAL = -1;
- public final static int NO_ROUNDING = 9;
- public final static int ROUND_ABOVE_5 = 5 ;
- public final static int ROUND_ABOVE_4 = 4;
- public final static int ROUND_ALWAYS = 0;
-
- //-----------------------------Implementation---------------------------
- /**
- * The maximum scale supported.
- *
- */
- private static final int MAXSCALE = 0x3fffffff; //Maximum scale.
-
-
-
- private int value[];
- private int scale;
- private boolean negative;
- //----------------------------------------------------------------------
- /**
- * The roundingValue is a digit between -1 and 9 that determines
- * rounding behavior.
- */
- private static int roundingValue = 4;
-
- /**
- * To avoid problems with negative carries,etc, we user a base 2^30;
- */
- static final int SRADIX = 30;
- private static final int BASE = 1<<SRADIX;
-
- // Useful masks
- private static final long MASK = 0x3fffffffL;
-
- public static final Bignum ZERO = new Bignum("0,0");
- public static final Bignum ONE = new Bignum(1,0);
- public static final Bignum TWO = new Bignum(2,0);
-
- //----------------------------------------------------------------------
-
- /**
- * Throws IllegalArgument exception is the scale is negative or
- * greater then MAXSCALE (0x3fffffffL).
- *
- */
- static private void verifyScale(int scale) {
-
- if (scale < 0) {
- throw new IllegalArgumentException("Scale is negative");
- }
- if (scale > MAXSCALE) {
- throw new IllegalArgumentException("Scale greater than maximum scale");
- }
- }
-
- /**
- * Compare the value of this Bignum to the value of the argument.
- * Returns 1 if this is greater than the argument,
- * -1 if this is less than the argument,
- * 0 if this is equal to the argument.
- * @param B A Bignum to compare.
- * @return 1 if this > B,0 if this = B,-1 if this < B.
- */
- public int compare(Bignum B) {
- if (negative == false && B.negative == false) {
- return (compareAbs(B));
- }
- if (negative == true && B.negative == false) {
- return (-1);
- }
- if (negative == false && B.negative == true) {
- return (1);
- }
- int r = compareAbs(B);
- if (r != 0) {
- r *= -1;
- }
- return (r);
- }
-
- /**
- * Private function used for arithmetic comparisons. Performs an
- * absolute comparison.
- *
- * @param A A Bignum to compare.
- * @return 1 if this > A,0 if this = A,-1 if this < A.
- */
- private int compareAbs(Bignum A) {
- Bignum B;
- if(A.scale == scale)
- B = A;
- else
- B = new Bignum(A,scale);
-
- //look for the first significant digit
- int sigA,sigB;
- for (sigB = B.value.length - 1;sigB > 0 && B.value[sigB] == 0 ; sigB-- );
- sigB++;
- for (sigA = value.length - 1 ;sigA > 0 && value[sigA] == 0 ; sigA--);
- sigA++;
- if (sigA > sigB)
- return (1);
- if (sigB > sigA)
- return (-1);
- if (sigA == 0 && sigB == 0)
- return (0);
- while (--sigA >= 0 ) {
- if (value[sigA] > B.value[sigA]) {
- return (1);
- }
- if (value[sigA] < B.value[sigA]) {
- return (-1);
- }
- }
- return (0);
- }
-
- /**
- * Private function used to initialize a Bignum using a string.
- * The radix is assumed to be 10
- * @param s A string containing the intended value of the Bignum.
- * @param scale The number of digits to the right of the decimal point.
- * Should be -1 if the scale is to be determined by the contents
- * of the argument string s.
- */
- private void init(String s, int iscale) {
- boolean scaleGiven = true;
- scale = 0;
- int mantVal = 0;
- if (iscale < 0) {
- scaleGiven = false;
- }
- int inScale = 0; //Scale computed from decimal point in s
-
-
- negative = false; //Default to positive
- if (scaleGiven) {
- value = new int[(s.length() + iscale)/3 + 1];
- } else {
- value = new int[s.length()/5 + 1];
- }
- int[] t1 = new int[1];
- t1[0] = 10;
- //int [] t1;
- boolean mant = false;
- boolean gotFirstDigit = false;
- boolean gotFirstExpDigit = false;
-
- for (int i = 0;i < s.length() ;i++ ) {
- char c = s.charAt(i);
- if (c >= '0' && c <= '9') {
- if (inScale != 0) {
- if(!mant)
- inScale++;
- }
- int a = Character.digit(c,10);
- if(mant ) {
- mantVal = mantVal * 10 + a;
- gotFirstExpDigit = true;
- }
- else {
- t1 = mulAndAdd(value,10,a);
- if(t1 != null)
- value = t1;
- gotFirstDigit = true;
- }
- continue;
- }
- if (c == '-') {
- if(mant ){
- if(!gotFirstExpDigit)
- mantVal = -mantVal;
- }
- else{
- if(!gotFirstDigit)
- negative = true;
- }
- continue;
- }
- if (c == '.' && inScale == 0) {
- inScale = 1;
- }
- if (c== 'E' || c =='e')
- mant = true;
- }//for
- if(mant) {
- if(inScale != 0)
- scale = inScale - 1;
- else
- scale = 0;
- if(mantVal < 0) {
- mantVal *= -1;
- divide((new Bignum(10,0)).pow(mantVal));
- }
- else
- value = mul0(value,(new Bignum(10,0)).pow(mantVal).value);
- if(scaleGiven)
- _setScale(iscale);
- return;
-
- }
- if (inScale != 0) {
- //did we find a decimal point in the string
- inScale--;
- scale = inScale;
- //if so, use it
- if (scaleGiven) {
- if (scale != iscale) {
- //the number of decimal places in string exceeds request
- _setScale(iscale);
- }
-
- }
- } else {
- // there was no decimal point in the string
- scale = 0;
- if (scaleGiven) {
- _setScale(iscale);
- }
- }
- }
-
- /**
- * Set the value of the Bignum to zeroes. The precision and
- * scale are retained.
- */
- private void zero() {
- negative = false;
- for (int i = 0; i < value.length; i++) {
- value[i] = 0;
- }
- }
-
- /**
- * Remove leading zeroes from the value of the Bignum. Zeroes to
- * the right of the decimal point are retained.
- *
- * <P>The precision is changed accordingly. One zero is retained
- * if all digits are zero and the scale is zero.
- */
- private void dropLeadingZeroes() {
- int i;
- for(i = value.length -1;i >= 0 && value[i] == 0;i--);
- if(i < 0) i = 0;
- if(++i >= value.length ) return;
- int[] nval = new int[i];
- System.arraycopy(value,0,nval,0,i);
- value = nval;
- }
- /**
- *Returns a new Bignum whose value equals the
- *integer part of the input argument. The fractional part, if any,
- *is dropped.
- *@param Bignum The input value to truncate
- *@returns A new Bignum equal to the integer value of the argument
- */
- public static Bignum truncate(Bignum in) {
- if(in.scale == 0)
- return new Bignum(in);
- int scaleFactor = in.scale - 1;
- int[] tval = new int[1];
- tval[0] = 0;
-
- int m1 = 9; //
- int m4 = 1000000000;
- int x = scaleFactor;
- for(;x >= m1;x -= m1 )
- tval = mul0(tval,m4);
- if(x > 0 )
- tval = mul0(tval,pow(10,x));
- tval = add0(in.value,tval);
- x = scaleFactor + 1;
- for(;x >= m1;x -= m1)
- div0(tval,tval,m4);
-
- if(x > 0)
- div0(tval,tval,pow(10,x));
- Bignum out = new Bignum(tval);
- out.scale = 0;
- out.negative = in.negative;
- return out;
-
- }
-
- /**
- * Set the number of the digits to the right of the decimal point.
- * The precision and value of the Bignum will be adjusted
- * accordingly. Note that changing the scale to a smaller value
- * may result in rounding the value.
- *
- * @param scale the character to be converted
- * @see Bignum#setRoundingOption
- */
- private void _setScale(int iscale) {
- verifyScale(iscale);
- if (iscale == scale) {
- return;
- }
- if(iscale > scale){
- for(int i = iscale - scale;i > 0;--i)
- value = mul0(value,10);
- scale = iscale;
- return;
- }
- int tempRoundingValue = roundingValue;
- //to round to the nearest even, first truncate.
- //Later, check to see if it the result of the truncation
- //is odd. If it is add 1;
- if(roundingValue == ROUND_STATISTICAL)
- tempRoundingValue = 9;
- //iscale < scale
- int scaleFactor = (scale - iscale) - 1;
- int[] tval = new int[1];
- tval[0] = 9 - tempRoundingValue;
-
- int m1 = 9; //this is approx log10 of BASE
- int m4 = 1000000000;
- int x = scaleFactor;
- for(;x >= m1;x -= m1 )
- tval = mul0(tval,m4);
- if(x > 0 )
- tval = mul0(tval,pow(10,x));
- value = add0(value,tval);
- x = scaleFactor + 1;
- for(;x >= m1;x -= m1)
- div0(value,value,m4);
-
- if(x > 0)
- div0(value,value,pow(10,x));
- if(roundingValue == ROUND_STATISTICAL) {
- //Check for an odd result
- if((value[0] & 0x00000001) == 0x00000001)
- value[0] += 1; //and add 1 it was odd
-
- }
- scale = iscale;
- }
- //---------------------------------------------------------------------
- /**
- * Algorithmic multiplication of two positive integers represented as
- * 32-bit integers. Knuth Algorithm M.
- *
- * u is required to be longer or equal to v.
- *
- */
- private static int[] mul0(int[] u, int[] v) {
- int n = u.length - 1;
- int m = v.length - 1;
- long k = 0;
-
- int[] w = new int[u.length + v.length];
- for (int j = 0; j <= n; j++) {
- k = 0;
- int q = j;
- for (int i = 0; i <= m; i++) {
- //
- long uv = u[j];
- long t = uv * v[i] + w[q] + k;
- w[(q++)] = (int)(t & MASK);
- k = t >> SRADIX;
- }
- for(;k != 0;) {
- long uv = w[q] + k ;
- w[q++] = (int) (uv & MASK);
- k = uv >> SRADIX;
- }
- //
-
- }
- if(w[w.length -1] != 0)
- return w;
-
- int ul = w.length - 1;
- for(;ul > 0 && w[ul] == 0;ul--);
- ul++;
- int[] w1 = new int[ul];
- System.arraycopy(w,0,w1,0,w1.length);
- return w1;
- }
-
- private static int[] mul0(int[] u, int v) {
- int n = u.length - 1;
- long k = 0;
- long x = v & MASK;
- int[] w = new int[u.length];
- if (x != 0) {
- for (int i = 0; i <= n; i++) {
- long uv = (u[i] & MASK) * x + k;
- w[i] = (int)(uv & MASK);
- k = uv >> SRADIX;
- }
- if(k != 0){
- int[] ww = new int[w.length + 1];
- System.arraycopy(w,0,ww,0,w.length);
- ww[ww.length - 1] = (int) k;
- w = ww;
- }
- }
- return w;
- }
-
-
- //------------------------------------------------------------------------
- /**
- * Quick add of two Bignum array values
- *
- */
- private static int[] add0(int[] u, int[] v) {
-
- int j=0;
- int ul = u.length - 1;
- for(;ul > 0 && u[ul] == 0;ul--);
-
- int vl = v.length - 1;
- for(;vl > 0 && v[vl] == 0;vl--);
-
- ul++;vl++;
-
- if(ul < vl){
- int[] temp = u;
- u = v;
- v = temp;
- int temp2 = ul;
- ul = vl;
- vl = temp2;
- }
- int[] w = new int[ul + 1];
-
- long carry = 0;
- long temp;
-
- for (j = 0; j < vl ; ++j) {
- temp = u[j] + v[j] + carry;
- carry = temp >> SRADIX;
- w[j] = (int) (temp & MASK);
- }
- for (; carry != 0 && j < ul; ++j) {
- temp = u[j] + carry;
- w[j] = (int)(temp & MASK);
- carry = temp >> SRADIX;
- }
- if(carry == 0 && j < ul) {
- for(;j < ul;++j) w[j] = u[j];
- }
- else{
- w[j] = (int) (carry & MASK);
- }
- return w;
- }
- //-------------------------------------------------------------------
- /**
- * Internal routine to quickly add an integer value to a Bignum value.
- *
- */
- private static int[] add0(int[] u, int v) {
- int j=0;
- int ul = u.length - 1;
- for(;ul > 0 && u[ul] == 0;ul--);
-
- int[] w = new int[ul++ + 1];
- long carry = 0;
-
- long temp = ((long)u[j] & MASK) + ((long)v & MASK);
- carry = temp >> SRADIX;
- w[j] = (int)(temp & MASK);
- for (++j; carry != 0 && j < ul; ++j) {
- temp = u[j] + carry;
- w[j] = (int) (temp & MASK);
- carry = temp >> SRADIX;
- }
- if(carry == 0 && j < ul) {
- for(;j < ul;++j) {w[j] = u[j];}
- }
- return w;
- }
- //---------------------------------------------------------------------
- /*
- * Subtraction of two positive integers represented as 32-bit
- * integers. See Knuth Algorithm S.
- *
- * This operation is not commutative, and u must be longer or equal
- * in length to v.
- *
- * See add0 for details on representation and implementation.
- */
- private static int[] sub0(int[] u, int[] v) {
-
- boolean borrow = false;
-
- int ul = u.length - 1;
- for(;ul > 0 && u[ul] == 0;ul--);
-
- int vl = v.length - 1;
- for(;vl > 0 && v[vl] == 0;vl--);
-
- int[] w = new int[ul + 1];
- int wj;
- int j = 0;
- for (; j <= vl;) {
- wj = u[j] - v[j] + (borrow?-1:0);
- w[j++] = (int)(wj & MASK);
- borrow = wj < 0;
- }
- if(borrow)
- {
- for (; j <= ul; ) {
- w[j] = (u[j] - (borrow?1:0));
- if(w[j++] >= 0) break;
- }
- }
- for(;j <= ul;j++)
- w[j] = u[j];
- return w;
- }
-
- //-----------------------------------------------------------------
- private static int div0(int[] quotient,int[] dividend,int divisor){
- long carry = 0;
- for(int i = dividend.length - 1;i >= 0;--i){
- long x = (dividend[i] & MASK) + (carry << SRADIX);
- quotient[i] = (int) (x/((long)divisor & MASK));
- carry = x % (long)divisor;
- }
- return (int)carry;
- }
-
-
- private static void div(Bignum dvdnd, Bignum div, Bignum quot) {
- int divlen = div.value.length - 1;
-
- int d1 = div.value[divlen]; //divisor must be at least 2 digits
- int d2 = div.value[divlen - 1];
- int[] dndVal = dvdnd.value;
- int[] divVal = div.value;
- int qx = quot.value.length - 1;
- long q;
- for (int j = dvdnd.value.length - 1; j>divlen; j--) {
- int dd0 = dndVal[j];
- int dd1 = dndVal[j-1];
- int dd2 = dndVal[j-2];
- long temp1 = (((long)dd0)<<SRADIX) + (long)dd1;
- if (dd0 == d1) {
- q = (BASE)-1;
- } else {
- q = temp1 / (long) d1;
- }
- for (;;) {
- long p1 = d2 * q;
- long p2 = temp1 - (d1 * q);
- p2= (p2<<SRADIX) + dd2;
- if(p1 > p2)
- q--;
- else
- break;
- }
- if(q == 0){
- quot.value[qx--] = 0;
- continue;
- }
- int k = j-divlen-1;
- long carry = 0;
- for (int dk = 0; dk <= divlen; dk++) {
- long x1 = divVal[dk] * q + carry;
- int x2 = dndVal[k] - (int)(x1 & MASK);
- if (x2<0) {
- dndVal[k++] = x2 + (BASE);
- carry = (x1>>SRADIX) + 1;
- } else {
- dndVal[k++] = x2;
- carry = (x1>>SRADIX);
- }//elseif
- }//for
- if (carry != 0){
- int temp = dndVal[k] - (int)carry;
- if(temp >= 0)
- dndVal[k] = temp;
- else{
- dndVal[k] = temp + (BASE);
- //the guess was too big! back it off by 1
- carry = 0;
- k = j - divlen -1;
- q--;
- for (int dk = 0; dk <= divlen; dk++) {
- long nv = divVal[dk] + dndVal[k] + carry;
- dndVal[k++] = (int)(nv & MASK);
- carry = nv>>SRADIX;
- }//for
- if (carry == 1)
- dndVal[k] =(int) ((dndVal[k]+1) & MASK);
- }//else
- }//if
- quot.value[qx--] = (int)q;
-
- }//for
-
- }
- /**
- * Private power integer function used in division
- * and scaling.
- * @arg b the integer base value.
- * @arg e the exponent to be used
- *@return an integer value calculated as b^e;
- */
- private static int pow(int b,int e){
- if(e == 0) return 1;
- if(e == 1) return b;
- int ans = b;
- int temp = 1;
- while(e != 1){
- if((e & 0x0001)==0x0001)
- temp *= ans;
- ans *= ans;
- e >>=1;
- }
- return ans * temp;
- }
- /**
- *Private routine that multiplies the val by integer m
- * and adds the integer a.
- *@Returns a new array, if a new one had to be allocated,
- *otherwise, returns null;
- */
- private static int[] mulAndAdd(int val[],int m, int a){
- int n = val.length - 1;
- long k = a & MASK;
- long x = m & MASK;
- int[] w = val;
- if (x!= 0) {
- for (int i = 0; i <= n; i++) {
- long uv = (val[i] & MASK) * x + k;
- w[i] = (int)(uv & MASK);
- k = uv >> SRADIX;
- }
- if(k != 0){
- int[] ww = new int[w.length + 1];
- System.arraycopy(w,0,ww,0,w.length);
- ww[ww.length - 1] = (int) (k & MASK);
- w = ww;
- }
- }
- return w==val?null:w;
- }
-
- /**
- * Private constructor that creates a Bignum from an
- * array of integers. This is used internally to optimize
- * certain operations.
- * @param valueArray an array of integers that are presumed to hold the
- * value of the new Bignum.
- */
- private Bignum(int[] valueArray){
- value = valueArray;
- negative = false;
- }
-
-
- //---------------------------------------------------------------------
- /**
- * Algorithmic multiplication of two positive integers represented as
- * 32-bit integers. Knuth Algorithm M.
- *
- * u is required to be longer or equal to v.
- *
- */
- private static int[] mul0(int[] u, int[] v, int[] x) {
- int[] w = x;
- int n = u.length - 1;
- while(u[n] == 0) n--;
- int m = v.length - 1;
- while(v[m] == 0) m--;
- if(m < 0 || n < 0) {
- if(w == null) w = new int[1];
- w[0] = 0;
- return w;
- }
- long k = 0,uv,t;
- int q =0, maxpos = 0;
- if (w == null || w.length < (n + m + 3))
- w = new int[n + m + 3];
- for (int j = 0; j <= n; j++) {
- k = 0;
- q = j;
- for (int i = 0; i <= m; i++) {
- //
- uv = u[j];
- t = uv * v[i] + w[q] + k;
- w[(q++)] = (int)(t & MASK);
- k = t >> SRADIX;
- }
- for(;k != 0;) {
- uv = w[q] + k ;
- w[q++] = (int) (uv & MASK);
- k = uv >> SRADIX;
- }
- if(q > maxpos)
- maxpos = q;
- //
-
- }
- return w;
-
- }
-
-
- }//Bignum
-
-
-